package edu.bu.CS893;

import android.net.*;
import android.app.*;
import android.os.*;
import android.widget.*;
import android.view.*;
import android.provider.*;
import android.database.*;
import android.content.*;

/** This is the main layout for the Facebook contact manager.  
 *   
 * @author Michael Braude
 */
public class FacebookContactManager extends Activity implements View.OnClickListener, ServiceConnection {
	
	/** This is the name of the Shared Preferences object where we store the user's login and password
	 * 
	 */
	private static String PREFS_NAME = "fbprefs";
	
	/** This is the main list view where the contacts are displayed.
	 */
	private ListView mListView = null;
	
	/** This is the contact view adapter.
	 * 
	 */
	private ContactViewAdapter mContactViewAdapter = null;
	
	/** This is the handler object that we use to throw 
	 * runnables onto the message queue.s
	 */
	private Handler mHandler;
	
	/** This is a text view that displays the No Contacts item if the
	 * user has no contacts.
	 * 
	 */
	private TextView mEmptyContactTextView = null;	
	
	/** This is the layout that is used to add new contacts 
	 * to the phone.
	 */
	private LinearLayout mAddContactLayout = null;

	/** This is the layout that is used to edit facebook login/password
	 * 
	 */
	private LinearLayout mEditPreferencesLayout = null;
	
	/** This button is pressed when the user adds a contact.
	 * 
	 */
	private Button mAddContactButton = null;
	
	/** This button is pressed when the user cancels adding a contact.
	 * 
	 */
	private Button mCancelContactButton = null;

	/** This button is pressed when the user saves preferences
	 * 
	 */
	private Button mCancelPreferencesButton;

	/** This button is pressed when the user cancels the preferences screen
	 * 
	 */
	private Button mSavePreferencesButton;
	
	/** This is the name edit text.
	 * 
	 */
	private EditText mNameEditText = null;
	
	/** This is the number edit text.
	 * 
	 */
	private EditText mNumberEditText = null;
	
	/** This is the login edit text.
	 * 
	 */
	private EditText mLoginEditText = null;
	
	/** This is the password edit text
	 * 
	 */
	private EditText mPasswordEditText = null;
	
	/**
	 * This allows us to use methods provided by the FacebookService Service
	 */
	private IFacebookService mFbService;

	
    /** Called when the activity is first created. 
      * 
      * @author Michael Braude
      * @since 7/2/2008
      */
    @Override
    public void onCreate(Bundle icicle) {
    	
        super.onCreate(icicle);
        setContentView(R.layout.main);
        
        this.mListView = (ListView)this.findViewById(R.id.list_view);
        this.mAddContactLayout = (LinearLayout)this.findViewById(R.id.add_contact_layout);
        this.mEditPreferencesLayout = (LinearLayout)this.findViewById(R.id.edit_preferences_layout);
        this.mAddContactButton = (Button)this.findViewById(R.id.add_button);
        this.mCancelContactButton = (Button)this.findViewById(R.id.cancel_button);
        this.mSavePreferencesButton = (Button)this.findViewById(R.id.save_preferences_button);
        this.mCancelPreferencesButton = (Button)this.findViewById(R.id.cancel_preferences_button);
        this.mEmptyContactTextView = (TextView)this.findViewById(R.id.empty_list_textview);
        this.mNameEditText = (EditText)this.findViewById(R.id.name_edit_text);
        this.mNumberEditText = (EditText)this.findViewById(R.id.number_edit_text);
        this.mLoginEditText = (EditText)this.findViewById(R.id.login_edit_text);
        this.mPasswordEditText = (EditText)this.findViewById(R.id.password_edit_text);    
        
        // Add a listener for the add contact button:
        mAddContactButton.setOnClickListener(this);
        mCancelContactButton.setOnClickListener(this);
        
        // Add a listener for the edit preferences buttons:
        mSavePreferencesButton.setOnClickListener(this);
        mCancelPreferencesButton.setOnClickListener(this);
                
        // Hidden until the user presses the add contact menu item:
        this.mAddContactLayout.setVisibility(View.GONE);

        // Hidden until the user presses the edit preferences menu item:
        this.mEditPreferencesLayout.setVisibility(View.GONE);
        
        // check for login and password saved in preferences
        SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
        String login = settings.getString("login", "");
        String password = settings.getString("password", "");
        
        if (!login.equals("") && !password.equals("")) {      
	        bindToFacebookService();
        }
        else {
        	// show preferences screen
        	this.mEditPreferencesLayout.setVisibility(View.VISIBLE);
        }
        
        // This will populate the contacts view:
        this.mHandler = new Handler();
        this.refreshAllContacts();
    }

    /** Binds to the FacebookService. If a connection already exists, destroys it first
     * 
     */
	private void bindToFacebookService() {
		Intent fbServiceIntent = new Intent("fbshuffle");
		
		if (mFbService != null) {
			unbindService(this);
			stopService(fbServiceIntent);
			mFbService = null;
		}
		
		// bind to FacebookService service
		bindService(fbServiceIntent, this, BIND_AUTO_CREATE);
	}
    
	/** Creates the options menu.
     * 
     * @author Michael Braude
     * @since 7/2/2008
     */
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {    	
    	super.onCreateOptionsMenu(menu);        
        menu.add(0, 0, "Add Contact");
        menu.add(0, 1, "Remove Contact");
        menu.add(0, 2, "Edit Preferences");
        return true;
    }
    
    /**
     * hide popup dialogs when menu button is clicked
     */
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {    	
    	mAddContactLayout.setVisibility(View.GONE);
    	mEditPreferencesLayout.setVisibility(View.GONE);
    	return super.onPrepareOptionsMenu(menu);
    };
    
    /** Listen for the middle button so we can launch the phone.
     * 
     */
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
    	
    	if((event.getAction() != KeyEvent.ACTION_DOWN) 	||
    	   (mContactViewAdapter == null)				||
    	   (mListView.getCount() == 0))
    		return super.onKeyDown(keyCode, event);
    	
    	// If an item is selected, launch the phone:
    	if(keyCode == KeyEvent.KEYCODE_CALL || keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
    		
    		Object selectedItem = this.mListView.getSelectedItem();
        	if(selectedItem != null) {
	        	Contact c = (Contact)selectedItem;
	        	Intent i = new Intent();
				Uri uri = Uri.parse("tel:" + c.getPhoneNumber());
				i.setAction(Intent.CALL_ACTION);
				i.setData(uri);
				this.startActivity(i);
	    		return true;
        	}    		
			
        	return false;
        	
    	}   	
    	
    	int selectedIndex = this.mListView.getSelectedItemPosition();
    	int newIndex = -1;
    	
    	ContactView oldView = (selectedIndex > -1)
    		? (ContactView)mContactViewAdapter.getView(selectedIndex, null, null)
    		: null;
    	
    	if(keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {    		
    		newIndex = (selectedIndex + 1 < mListView.getCount()) ? selectedIndex + 1 : 0;    		
    		
    	} else if(keyCode == KeyEvent.KEYCODE_DPAD_UP) {    		
    		newIndex = (selectedIndex == 0) ? mListView.getCount() - 1 : selectedIndex - 1;
        	
    	}    
    	
    	if(newIndex > -1) {
    		
    		mListView.setSelection(newIndex);    		
    		ContactView newView = (ContactView)mContactViewAdapter.getView(newIndex, null, null);
    		
    		if(newView != null)
    			newView.setIsSelected(true);
    		
    		if(oldView != null)
    			oldView.setIsSelected(false);
			
        	return true;
        	
    	}
    	
    	return super.onKeyDown(keyCode, event);
    	
    }
    
    /** Throw up new activities based on the ID.
     * 
     */
    @Override
    public boolean onOptionsItemSelected(Menu.Item item){
    	
    	switch(item.getId()) {
        
    	// Throws up the add contact view:
    	case 0:
        	mNameEditText.setText("");
        	mNumberEditText.setText("");
        	mAddContactLayout.setVisibility(View.VISIBLE);
        	return true;
        	
        // Remove the currently selected contact:
        case 1:
        	
        	Object selectedItem = this.mListView.getSelectedItem();
        	if(selectedItem != null) {        		
        	
	        	Contact c = (Contact)selectedItem;
	        		        	
	        	Uri deleteURI = Contacts.People.CONTENT_URI;
	        	deleteURI = deleteURI.buildUpon().appendPath(c.getID()).build();
	        	this.getContentResolver().delete(deleteURI, null, null);
	        	
	        	int selectedIndex = this.mListView.getSelectedItemPosition();
	        	if(selectedIndex == this.mListView.getCount() - 1)
	        		selectedIndex--;
	        	
	        	this.mListView.setSelection(selectedIndex);
	        	
	        	this.mContactViewAdapter.removeContact(c);	        	
	        	this.refreshAllContacts();
	        	
        	}
        	
        	this.mAddContactLayout.setVisibility(View.GONE);
        	return true;
        	
        // Edit preferences
        case 2:
        	SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
        	mLoginEditText.setText(settings.getString("login", ""));
        	mPasswordEditText.setText(settings.getString("password", ""));
        	mEditPreferencesLayout.setVisibility(View.VISIBLE);
        	return true;
        }
    	
    	return false;
    	
    }

    /** Called when the add or cancel button is pressed.  If the add
     * button was pressed, add a contact to the contacts database!
     * 
     * @author Michael Braude
     * @since 7/2/2008
     */
    public void onClick(View v) {
        
    	if (v == this.mAddContactButton) {

    		ContentValues contactValues = new ContentValues();
    		contactValues.put(Contacts.People.NAME, this.mNameEditText.getText().toString());    		
    		
    		// This will add the person:
    		Uri uri = this.getContentResolver().insert(Contacts.People.CONTENT_URI, contactValues);
    		
    		// Now we need to add a number to this person:
    		contactValues.clear();
    		contactValues.put(Contacts.Phones.PERSON_ID, uri.getLastPathSegment());
    		contactValues.put(Contacts.Phones.NUMBER, this.mNumberEditText.getText().toString());
    		this.getContentResolver().insert(Contacts.Phones.CONTENT_URI, contactValues);
    		
    		refreshAllContacts();
    		
        }
    	
    	else if (v == this.mSavePreferencesButton) {
    		// load old login and password

    		SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);

    		String aOldLogin = settings.getString("login", "");
    		String aOldPassword = settings.getString("password", "");
    		String aNewLogin = mLoginEditText.getText().toString().trim();
    		String aNewPassword = mPasswordEditText.getText().toString().trim();
    		
    		if (!aOldLogin.equals(aNewLogin) || !aOldPassword.equals(aNewPassword)) {
	    		// Save login and password as preferences
	    		SharedPreferences.Editor editor = settings.edit();
	    		editor.putString("login", aNewLogin);
	    		editor.putString("password", aNewPassword);
	
	    	    editor.commit();
	    	    
	    	    // re-initialize service with new login/password
	    	    bindToFacebookService();
    		}
    	}
    	
    	// attempt to hide both contact and preferences dialog 
    	mAddContactLayout.setVisibility(View.GONE);
    	mEditPreferencesLayout.setVisibility(View.GONE);

	} 
    
    /** Refreshes the entire contact list.
     * 
     * @author Michael Braude
     * @since 7/2/2008
     */
    private void refreshAllContacts() {
    	
    	if(mContactViewAdapter == null) {
    		mContactViewAdapter = new ContactViewAdapter(this);
    		mListView.setAdapter(mContactViewAdapter);
    	}
        
    	// Query Android for a list of contacts: 
		Cursor peopleCursor = this.managedQuery(Contacts.People.CONTENT_URI, null, null,null);

		// Read all contacts into the adapter:
		while(peopleCursor.next()) {
			
			int columnIndex = peopleCursor.getColumnIndex(Contacts.People.NAME);
			final String contactName = peopleCursor.getString(columnIndex);			
			
			Contact c = mContactViewAdapter.findByName(contactName);
			if(c == null) {
				
				c = new Contact();
			
				columnIndex = peopleCursor.getColumnIndex(Contacts.People._ID);
				long ID = peopleCursor.getLong(columnIndex);
				c.setID(String.valueOf(ID));		
				c.setName(contactName);
				
				// Grab the number from the numbers table:
				Uri phonesURI = Contacts.Phones.CONTENT_URI;
				phonesURI = phonesURI.buildUpon().appendPath(String.valueOf(ID)).build();
				Cursor phoneCursor = this.managedQuery(phonesURI, null, null, null);
				
				if(phoneCursor.next()) {			
					columnIndex = phoneCursor.getColumnIndex(Contacts.Phones.NUMBER);
					c.setPhoneNumber(phoneCursor.getString(columnIndex));
				}
				
				mContactViewAdapter.addContact(c);
			
			}
        	
			// TO DO: throw this into a runnable queue:			
        	// look up this user's status on facebook	
			final Contact contact = c;
			final ContactView view = mContactViewAdapter.getViewByName(contactName);
			
			if(mFbService != null && view != null) {
				
				// Post this into the handlers' runnable queue to make 
				// it pseudo multi-threaded:
				mHandler.post(new Runnable() {
					
					public void run() {
						
						try {
			        		
							String contactName = contact.getName();
							contact.setStatusMessage(mFbService.getStatusFromName(contactName));
							contact.setProfilePictureURL(mFbService.getPicFromName(contactName));
				        	view.refreshFields();
			        		
			        	}
			        	catch(Exception e) {
			        		// Ignored...
			        		
			        	}
			        	
					}
					
				});
			
			}
        	
		}
		
		if(mContactViewAdapter.getCount() > 0) {
			
			mEmptyContactTextView.setVisibility(View.GONE);
		
			int selectedIndex = mListView.getSelectedItemPosition();
			if(selectedIndex == -1) {
				selectedIndex = 0;
				mListView.setSelection(selectedIndex);
			}
			
			// Select the first item:
			ContactView view = (ContactView)mContactViewAdapter.getView(selectedIndex, null, null);
			view.setIsSelected(true);			
			
		}
		
		mListView.invalidateViews();
		
    }

    
    /** Called when the application is connected to a service.
     * 
     */
	public void onServiceConnected(ComponentName name, IBinder service) {
		if (service instanceof IFacebookService) {
			mFbService = (IFacebookService) service;
						
			refreshAllContacts();
		}
	}

	/** Does nothing for now. 
	 * 
	 */
	public void onServiceDisconnected(ComponentName name) {
		// TODO Auto-generated method stub
		
	}

    
}